﻿//**************************
//开发人员：Morning Sun QQ:576830428  微信:MorningSun0125
//业务范围：网站开发、小程序开发、web应用开发,桌面程序开发,工控类软件开发等
//开发日期：2016年1月10日
//版本号：Version 3.0 CopyRight 2011-2029
//**************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.IO;
using System.Threading;
using System.Net.Sockets;
using System.Net;


namespace FileClient
{
    public partial class Formclient : Form
    {
        #region 变量
        /// <summary>
        /// 拖动位置
        /// </summary>
        private Point MousePoint;
        /// <summary>
        /// 是否为鼠标左键
        /// </summary>
        private bool LeftFlag;
        /// <summary>
        /// 链接的服务器socket
        /// </summary>
        Socket ServerSocket;
        /// <summary>
        /// socket配置信息
        /// </summary>
        SocketConfig socketconfig;
        /// <summary>
        /// 发送数据包大小
        /// </summary>
        int SendPacketSize = 1024 * 1024;
        /// <summary>
        /// 接收数据包大小
        /// </summary>
        int ReceivePacketSize = 1024 * 1024;
        /// <summary>
        /// 发送周期默认500毫秒，1000毫秒等于1s
        /// </summary>
        int SendInterval = 500;
        /// <summary>
        /// 接收数据的线程
        /// </summary>
        Dictionary<string, Thread> ReceiveDataDic = new Dictionary<string, Thread>();
        /// <summary>
        /// 命令集合
        /// </summary>
        List<string> ListCMD = new List<string>();
        /// <summary>
        /// 发送命令线程
        /// </summary>
        Thread ThreadSend;
        /// <summary>
        /// 是否在传输文件
        /// </summary>
        bool TransferFile = false;
        /// <summary>
        /// 末次通讯时间
        /// </summary>
        DateTime LastMsgTime=DateTime.Now;
        #endregion


        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public Formclient()
        {
            InitializeComponent();
            this.FormBorderStyle = FormBorderStyle.None;

            #region 服务器信息
            string Path = Environment.CurrentDirectory + @"\system.ini";
            if (File.Exists(Path))
            {
                try
                {
                    FileInfo fi = new FileInfo(Path);
                    FileStream fs = new FileStream(Path, FileMode.Open);
                    byte[] data = new byte[fs.Length];
                    fs.Read(data, 0, data.Length);
                    fs.Close();
                    fs.Dispose();
                    string Config = System.Text.Encoding.UTF8.GetString(data);
                    TbxIP.Text = Config.Split(';')[0];
                    TbxPort.Text = Config.Split(';')[1];
                }
                catch(Exception ex)
                {
                
                }
            }
            #endregion

            #region 工具栏
            WinIcon.Parent = WinTitlePic;
            labWinTitle.Parent = WinTitlePic;
            labWinMin.Parent = WinTitlePic;
            labWinClose.Parent = WinTitlePic;
            labWinMin.BackgroundImage = global::FileClient.Properties.Resources.winMin;
            labWinClose.BackgroundImage = global::FileClient.Properties.Resources.winClose;
            #endregion

            #region 工作区
            gpboxlog.Parent = WorkPic;
            gpboxOp.Parent = WorkPic;
            gpbserver.Parent = WorkPic;
            #endregion

            MsgBox.AppendText("定制联系微信:MorningSun0125");
        }
        #endregion


        #region   最小化窗体
        /// <summary>
        /// 最小化窗体
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnMin_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }
        #endregion


        #region 关闭窗体
        /// <summary>
        /// 关闭窗体
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnClose_Click(object sender, EventArgs e)
        {
            try
            {
                HeartBeatTimer.Stop();
                //停止发送线程
                ThreadSend.Abort();
                //关闭socket
                if (ServerSocket.Connected)
                {
                    ServerSocket.Close();
                }
                //关闭线程
                foreach (var receive in ReceiveDataDic)
                {
                    if (receive.Value.IsAlive)
                    {
                        receive.Value.Abort();
                    }
                }
            }
            catch (Exception ex)
            {

            }
            System.Environment.Exit(0);
            this.Close();
        }
        #endregion


        #region  最小化按钮效果
        /// <summary>
        /// 鼠标悬浮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void labWinMin_MouseHover(object sender, EventArgs e)
        {
            labWinMin.BackgroundImage = global::FileClient.Properties.Resources.winMinPressed;
        }


        /// <summary>
        /// 鼠标离开
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void labWinMin_MouseLeave(object sender, EventArgs e)
        {
            labWinMin.BackgroundImage = global::FileClient.Properties.Resources.winMin;
        }
        #endregion


        #region  关闭按钮效果
        /// <summary>
        /// 关闭按钮悬浮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void labWinClose_MouseHover(object sender, EventArgs e)
        {
            labWinClose.BackgroundImage = global::FileClient.Properties.Resources.winClosePressed;
        }


        /// <summary>
        /// 关闭按钮鼠标经过
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void labWinClose_MouseLeave(object sender, EventArgs e)
        {
            labWinClose.BackgroundImage = global::FileClient.Properties.Resources.winClose;
        }
        #endregion


        #region 窗体拖动
        private void WinTitlePic_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                MousePoint = new Point(-e.X, -e.Y); //得到变量的值
                LeftFlag = true;                  //点击左键按下时标注为true;
            }
        }

        private void WinTitlePic_MouseMove(object sender, MouseEventArgs e)
        {
            if (LeftFlag)
            {
                Point mouseSet = Control.MousePosition;
                mouseSet.Offset(MousePoint.X, MousePoint.Y);  //设置移动后的位置
                Location = mouseSet;
            }
        }

        private void WinTitlePic_MouseUp(object sender, MouseEventArgs e)
        {
            if (LeftFlag)
            {
                LeftFlag = false;//释放鼠标后标注为false;
            }
        }
        #endregion


        #region  按钮效果
        /// <summary>
        /// 鼠标离开
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_MouseLeave(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            btn.BackgroundImage = global::FileClient.Properties.Resources.btn;
        }


        /// <summary>
        /// 鼠标悬浮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_MouseHover(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            btn.BackgroundImage = global::FileClient.Properties.Resources.btn_over;
        }
        #endregion






        #region 链接服务端
        /// <summary>
        /// 链接服务端
        /// </summary>
        private void ConnectServer()
        {           
            IPEndPoint ServerIP = socketconfig.GetIPEndPoint();
            ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //连接服务器
            try
            {
                AddMsg("Server:Conect Server");
                ServerSocket.Connect(ServerIP);
                if (ServerSocket.Connected)
                {
                    AddMsg("Server:Conect Server Success");
                    //开启发送数据线程
                    ThreadSend = new Thread(SendData);
                    ThreadSend.Start();
                    ImgBoxStatus.Image = global::FileClient.Properties.Resources.green;
                }                
            }
            catch (Exception)
            {
                AddMsg("Server:Conect Server  Failed");
                btnStart.Enabled = true;
                btnStop.Enabled = false;
                ImgBoxStatus.Image = global::FileClient.Properties.Resources.red;
                return;
            }
            
            //启用一个线程接收数据
            Thread threadreceive = new Thread(delegate() { ReceiveData(ServerSocket); });
            threadreceive.Start();
            if (!ReceiveDataDic.ContainsKey(ServerIP.Address.ToString()))
            {
                ReceiveDataDic.Add(ServerIP.Address.ToString(), threadreceive);
            }
            else
            {
                ReceiveDataDic[ServerIP.Address.ToString()] = threadreceive;
            }

            //启用Tcp心跳
            Invoke(new MethodInvoker(delegate()
            {
                HeartBeatTimer.Enabled = true;
                HeartBeatTimer.Start();
            })); 
        }
        #endregion


        #region 接收数据
        /// <summary>
        /// 接收数据
        /// </summary>
        private void ReceiveData(Socket ClientSocket)
        {
            if (ClientSocket != null)
            {
                try
                {
                    //创建一个新文件        
                    FileStream MyFileStream = null;
                    //同步文件名
                    string SyncFileName = "";
                    //同步文件总长度
                    int SyncFileLength = 0;
                    //缓冲区
                    byte[] bytes = new byte[ReceivePacketSize];
                    //当前IP
                    IPEndPoint ClientIP = (IPEndPoint)ClientSocket.RemoteEndPoint;

                    while (true)
                    {
                        bytes = new byte[ReceivePacketSize];
                        //接收数据
                        int butter = ClientSocket.Receive(bytes, 0, ReceivePacketSize, SocketFlags.None);
                        try
                        {
                            #region  接收数据
                            if (butter > 0)
                            {
                                LastMsgTime = DateTime.Now;

                                //字节数组首位为协议位，0表示命令，1表示文件
                                #region 命令解析
                                if (!TransferFile)//表示消息
                                {
                                    string CMD = System.Text.Encoding.UTF8.GetString(bytes, 0, butter).TrimEnd('\0');
                                    AddMsg(CMD);
                                    if (CMD.Substring(0, 6) == "NewDir")//创建文件夹
                                    {
                                        string Path = CMD.Substring(7, CMD.Length - 7);
                                        if (!Directory.Exists(Path))//不存在则创建
                                        {
                                            FileHelp.CreateDir(Path);
                                        }
                                        //回复信息
                                        AddCMD("Over," + ClientIP.Address + "," + DateTime.Now);
                                    }
                                    else if (CMD.Substring(0, 7) == "NewFile")//创建文件
                                    {
                                        string Path = CMD.Substring(8, CMD.Length - 8);
                                        FileHelp.FileCreate(Path);
                                        //回复信息
                                        AddCMD("Over," + ClientIP.Address + "," + DateTime.Now);
                                    }
                                    else if (CMD.Substring(0, 3) == "Del")//删除命令
                                    {
                                        #region 删除命令
                                        string Path = CMD.Substring(4, CMD.Length - 4);
                                        if (FileHelp.CheckFileDir(Path) == 0)//删除文件夹
                                        {
                                            FileHelp.DeleteDir(Path);
                                        }
                                        if (FileHelp.CheckFileDir(Path) == 1)//删除文件
                                        {
                                            FileHelp.FileDel(Path);
                                        }
                                        #endregion
                                        //回复信息
                                        AddCMD("Over," + ClientIP.Address + "," + DateTime.Now);
                                    }
                                    else if (CMD.Substring(0, 6) == "Rename")//重命名
                                    {
                                        string Path = CMD.Substring(7, CMD.Length - 7);
                                        string OldPath = Path.Split('\r')[0];
                                        string NewPath = Path.Split('\r')[1];
                                        if (FileHelp.CheckFileDir(OldPath) == 0)
                                        {
                                            FileHelp.MoveDir(OldPath, NewPath);
                                        }

                                        if (FileHelp.CheckFileDir(OldPath) == 1)
                                        {
                                            FileHelp.FileMove(OldPath, NewPath);
                                        }
                                        //回复信息
                                        AddCMD("Over," + ClientIP.Address + "," + DateTime.Now);
                                    }
                                    else if (CMD.Substring(0, 8) == "SyncFile")//同步文件
                                    {
                                        SyncFileName = CMD.Split(',')[1];
                                        MyFileStream = new FileStream(SyncFileName, FileMode.Create, FileAccess.Write);
                                        SyncFileLength = int.Parse(CMD.Split(',')[2].Split('=')[1]);
                                        TransferFile = true;
                                    }
                                }
                                #endregion

                                #region 文件接收
                                else //表示文件
                                {
                                    if (SyncFileLength <= butter)//表示最后一个包包含了0
                                    {
                                        MyFileStream.Write(bytes, 0, SyncFileLength);
                                        MyFileStream.Close();
                                        MyFileStream.Dispose();
                                        AddMsg("Over:length=" + butter);

                                        TransferFile = false;
                                        //回复信息
                                        AddCMD("Over," + ClientIP.Address + "," + DateTime.Now);
                                        AddMsg("接收完毕");
                                    }
                                    else
                                    {
                                        MyFileStream.Write(bytes, 0, butter);
                                        SyncFileLength = SyncFileLength - butter;
                                        AddMsg("Receive:length=" + butter);                                        
                                    }
                                }
                                #endregion
                            }
                            #endregion
                        }
                        catch (Exception ex)
                        {

                        }
                    }
                }
                catch (Exception ex)
                {
                    try
                    {
                        ClientSocket.Close();
                    }
                    catch (Exception exc)
                    {
                    }
                }
            }
        }
        #endregion


        #region 发送命令
        /// <summary>
        /// 发送命令
        /// </summary>
        private void SendData()
        {
            while (true)
            {
                if (ListCMD != null && ListCMD.Count > 0)
                {
                    string CMD = ListCMD[0];
                    //发送消息
                    SendData(CMD);
                    ListCMD.Remove(CMD);
                    System.Threading.Thread.Sleep(SendInterval);
                }
            }
        }
        #endregion    


        #region 命令集合
        /// <summary>
        /// 命令集合
        /// </summary>
        /// <param name="CMD"></param>
        private void AddCMD(string CMD)
        {
            if (!ListCMD.Contains(CMD))
            {
                ListCMD.Add(CMD);
            }
        }
        #endregion


        #region 发送信息
        /// <summary>
        /// 发送信息
        /// </summary>
        /// <param name="cmdstr"></param>
        private void SendData(string cmdstr)
        {
            if (ServerSocket.Connected)
            {
                #region 发送信息
                try
                {
                    byte[] data = System.Text.Encoding.UTF8.GetBytes(cmdstr);
                    ServerSocket.Send(data, 0, data.Length, SocketFlags.None);
                }
                catch (Exception ex)
                {
                    //ImgBoxStatus.Image = global::FileClient.Properties.Resources.red;
                }
                #endregion
            }
        }
        #endregion
        

        #region 启动服务
        /// <summary>
        /// 启动服务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            TransferFile = false;
            LastMsgTime = DateTime.Now;

            string CheckResult=CheckConfig();
            if (CheckResult == "")
            {
                btnStart.Enabled = false;
                btnStop.Enabled = true;
                ImgBoxStatus.Image = global::FileClient.Properties.Resources.yellow;
                ///初始化配置信息
                socketconfig = new SocketConfig(TbxIP.Text.Trim(), TbxPort.Text.Trim());
                AddMsg("Server:Server Start!");
                ConnectServer();
            }
            else
            {
                MessageBox.Show(CheckResult,"提示",MessageBoxButtons.OK,MessageBoxIcon.Information);
            }
        }
        #endregion


        #region 停止服务
        /// <summary>
        /// 停止服务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            try
            {
                HeartBeatTimer.Stop();
                //停止发送线程
                ThreadSend.Abort();
                //关闭socket
                if (ServerSocket != null && ServerSocket.Connected)
                {
                    ServerSocket.Close();
                }
                //关闭线程
                foreach (var receive in ReceiveDataDic)
                {
                    if (receive.Value.IsAlive)
                    {
                        receive.Value.Abort();
                    }
                }
                AddMsg("Server:Stop Server!");
            }
            catch (Exception ex)
            {

            }
            btnStart.Enabled = true;
            btnStop.Enabled = false;
            ImgBoxStatus.Image = global::FileClient.Properties.Resources.gray;
        }
        #endregion


        #region 保存配置
        /// <summary>
        /// 保存配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSave_Click(object sender, EventArgs e)
        {
            string CheckResult=CheckConfig();
            if (CheckResult == "")
            {
                string Path = Environment.CurrentDirectory + @"\system.ini";
                byte[] data = System.Text.Encoding.UTF8.GetBytes(TbxIP.Text.Trim()+";"+TbxPort.Text.Trim());
                FileStream fs = new FileStream(Path, FileMode.Create);
                fs.Write(data, 0, data.Length);
                fs.Flush();
                fs.Close();
                fs.Dispose();
                MessageBox.Show("保存成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                MessageBox.Show(CheckResult,"提示",MessageBoxButtons.OK,MessageBoxIcon.Information);
            }
        }
        #endregion


        #region 清空日志
        /// <summary>
        /// 清空日志
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClear_Click(object sender, EventArgs e)
        {
            MsgBox.Clear();
        }
        #endregion        


        #region 发送测试
        /// <summary>
        /// 发送测试
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnTest_Click(object sender, EventArgs e)
        {
            AddCMD(socketconfig.ServerIP + ",Client:Test");
        }
        #endregion


        #region Tcp心跳
        /// <summary>
        /// 心跳包检测
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HeartBeatTimer_Tick(object sender, EventArgs e)
        {
            if (!ServerSocket.Connected)//链接断开则重连
            {
                try
                {
                    ConnectServer();
                }
                catch (Exception ex)
                {
                    //ImgBoxStatus.Image = global::FileClient.Properties.Resources.red;
                }
            }
            else//链接存在发送心跳
            {
                //如果没有发送命令且已经超过2分钟没通讯了,则发送心跳数据
                if (((DateTime.Now - LastMsgTime).TotalMinutes >= 2)&&(ListCMD.Count<=0))
                {
                    AddCMD(socketconfig.ServerIP + ",Client:Timer");
                }
            }
        }
        #endregion    


        #region 检测配置
        /// <summary>
        /// 检测配置
        /// </summary>
        /// <returns></returns>
        private string CheckConfig()
        {
            string IP = TbxIP.Text.Trim();
            string Port = TbxPort.Text.Trim();
            string Result="";
            if (FormValidate.IsEmpt(IP))
            {
                Result = "请填写服务器IP!"; 
            }
            else if (FormValidate.IsEmpt(Port))
            {
                Result = "请填写服务器端口!";
            }
            else if (!FormValidate.IsIP(IP))
            {
                Result = "服务器IP格式错误!";
            }
            else if (!FormValidate.IsNumber(Port))
            {
                Result = "服务器端口必须是数字!";
            }
            return Result;
        }
        #endregion


        #region 更新消息
        /// <summary>
        /// 更新消息
        /// </summary>
        /// <param name="Msg"></param>
        private void AddMsg(string Msg)
        {
            Invoke(new MethodInvoker(delegate()
            {
                if (MsgBox.Text.Length > 5000)
                {
                    MsgBox.Clear();
                }
                MsgBox.AppendText("DateTime:" + DateTime.Now + "," + Msg + "\r");
                MsgBox.ScrollToCaret();
            }));
        }
        #endregion


        #region  构建协议
        /// <summary>
        /// 构建协议
        /// </summary>
        /// <param name="Agreement">协议类型,0:消息,1:文件</param>
        /// <param name="?">字节流</param>
        /// <returns></returns>
        private byte[] MakeAgreement(int Agreement, byte[] data)
        {
            //生成的协议字节流
            byte[] ReturnByte = new byte[data.Length + 1];
            if (Agreement == 0)
            {
                ReturnByte[0] = 0;
            }
            else
            {
                ReturnByte[0] = 1;
            }
            Buffer.BlockCopy(data, 0, ReturnByte, 1, data.Length);
            return ReturnByte;
        }
        #endregion
    }
}
